var db = require('./db-config.js');
var api = require('./footballAPI.js');
var sudo = "sudo";
/**
 * Sign up for new user
 * @param {String} name
 */
var signup = function(name, password) {
    db.users.insert({
        name : name,
        password : password,
        points : 0,
        mvp : null,
        kingOfGoals : null,
        kingOfAssists : null,
        champion : null,
        leastGoalsConceded : null,
        mostGoalsScored : null,
        /* QUALIFIERS*/
        qualifiers : [],
        /* GROUP STAGE*/
        groups : [],
        /* KNOCKOUT STAGE*/
        knockout : []
    });
    init(name);
};

/**
 * Boolean function - if the game is openable it ALSO OPENS THE GAME (so we don't need to work twice)
 * @param {Object} i_name
 * @param {Object} match_id
 * @param {level} rules of how much points to take
 * @param {Object} callback
 * @return true if the game is openable, false otherwise
 */
var isGameOpenable = function(i_name, match_id, i_levelRules, callback) {
    var pointsNeeded = i_levelRules.costToOpen;
    db.users.findOne({
        name : i_name
    }, function(err, result) {
        if (err || !result) {
            //Not good! User not found
            console.log("users - User not found so can not check games");
            callback(false);
        } else {
            //User found - lets see if he has enough points, if he does, make the game true and return true
            if (result.points < pointsNeeded) {
                //User does NOT have enough points
                callback(false);
            } else {
                //User has enough points to open the game, lets open it
                db.users.update({
                    name : i_name,
                    'knockout.match_id' : match_id
                }, {
                    $set : {
                        'knockout.$.away' : true,
                        'knockout.$.home' : true,
                    }
                });
                callback(true);
            }

        }
    });
};

/***
 * Log in the player
 */
var userExists = function(i_name, callback) {
    db.users.findOne({
        name : i_name,
    }, function(err, result) {
        //No user were found
        if (err || !result || result.length < 1 || result == null) {
            callback(true);
        } else {
            callback(false);
        }

    });
};

/**
 * Scans the DB and callbacks false if name exists, true if doesn't
 * This is called ONLY when signing up a new Collection - so if it doesn't exist - add it to SUDO!
 */
var collectionExists = function(i_collection, callback) {
    db.users.findOne({
        name : sudo
    }, {
        collections : 1
    }, function(err, result) {
        if (err || !result) {
            //Problem! Should not happen
        } else {
            var sudoCollections = result.collections;
            for (var i = 0; i < sudoCollections.length; i++) {
                //Go over the collections and check if name exists
                if (sudoCollections[i].name == i_collection) {
                    //Name exists!!!
                    callback(false);
                }

            }//Name doesn't exist - callback true
            callback(true);
        }
    });
};
/**
 * Changes the name of the player
 */
var editProfile = function(newName, oldName) {
    db.users.update({
        name : oldName
    }, {
        $set : {
            name : newName
        }
    });
};
/**
 * Logs in this user to this collection, returns true if the user is in this collection
 * returns false if this user is signed in to a DIFFERENT collection!!
 */
var loginCollection = function(i_name, i_collection, i_collectionPass, callback) {
    var realPassword = null;
    //First we get the real password from sudo (if exists!!)
    db.users.findOne({
        name : sudo
    }, {
        collections : 1
    }, function(err, sudoCollections) {
        if (err || !sudoCollections) {
            console.log("users: Error getting Sudo's collections - " + err);
        } else {
            for (var i = 0; i < sudoCollections.collections.length; i++) {
                if (sudoCollections.collections[i].name == i_collection) {
                    realPassword = sudoCollections.collections[i].password;
                }
            };
            //Now if the collection existed - its in realPassword
            if (realPassword != null) {
                //This is the case where the collection existed
                if (realPassword == i_collectionPass) {
                    //The login is successfull!! put this user in this collection
                    db.users.update({
                        name : i_name
                    }, {
                        $set : {
                            collection : i_collection
                        }
                    });
                    //Callback true
                    callback(true);
                } else {
                    //Wrong password!
                    callback(false);
                }
            } else {
                //This is the case where the collection DID NOT Exist! so this is a new collection
                console.log("Added " + i_name + " to " + i_collection);
                db.users.update({
                    name : i_name
                }, {
                    $set : {
                        collection : i_collection
                    }
                });
                callback(true);

            }

        }
    });
};
/***
 * Log in the player
 */
var login = function(i_name, i_pass, callback) {
    db.users.findOne({
        name : i_name,
        password : i_pass

    }, function(err, result) {
        //No user were found
        if (err || !result || result.length < 1 || result == null) {
            callback(false);
        } else {
            callback(true);
        }

    });
};

/**
 * Changes this users collection to null
 */
var removeCollectionFromUser = function(i_name) {
    db.users.update({
        name : i_name
    }, {
        $set : {
            collection : null
        }
    }, function(err, result) {
        console.log(err);
    });
};
/**
 * Lists all the users, sorted, and only shows points,name,champion,and next game bet
 */
var listAllUsers = function(i_collection, callback) {
    db.users.find({
        collection : i_collection
    }, {
        points : true,
        name : true,
        champion : true
    }).sort({
        points : -1
    }, function(err, sortedUsers) {
        callback(sortedUsers);
    });
};

/**
 * Lists all the world users
 */
var listWorldUsers = function(callback) {
    db.users.find({
    }, {
        points : true,
        name : true,
        champion : true
    }).sort({
        points : -1
    }, function(err, sortedUsers) {
        callback(sortedUsers);
    });
};

/***
 * Places a bet in the group stage
 * @param {String} groupNum (0-7)
 * @param {Object} Match_id to bet on
 * @param {Array} score
 * @param {Object} name
 */
var insertGroupMatchBet = function(i_groupNum, i_match, i_score, i_name) {
    var parsedScore = [parseInt(i_score[0]), parseInt(i_score[1])];
    db.users.update({
        name : i_name,
        "groups.match_id" : i_match
    }, {
        $set : {
            "groups.$.score" : parsedScore
        }
    });
};
/***
 * @param {String} groupName
 * @param {Array} bet [<team_name>,<team_name>]
 * @param {String} name
 */
var insertQualifiersBet = function(i_groupNum, i_bet, i_name) {
    var rankedFirst = i_bet[0];
    var rankedSecond = i_bet[1];
    db.users.update({
        name : i_name,
        'qualifiers.groupName' : i_groupNum,
    }, {
        $set : {
            'qualifiers.$.rankedFirst' : rankedFirst,
            'qualifiers.$.rankedSecond' : rankedSecond
        }
    });
};
/**
 * Place a bet in the tournament stage
 * @param {Object} bets
 * @param {Object} name
 */
var insertTournamentBet = function(i_bets, i_name) {
    console.log("Inserting Tournament Bets - " + i_name);
    db.users.update({
        name : i_name
    }, {
        $set : {
            kingOfAssists : i_bets.kingOfAssists.trim(),
            kingOfGoals : i_bets.kingOfGoals.trim(),
            champion : i_bets.champion.trim(),
        }
    });
};

var userProfile = function(i_name, callback) {
    db.users.findOne({
        name : i_name
    }, function(err, result) {
        if (err || !result) {
            callback(null);
        } else {
            callback(result);
        }
    });
};

/**
 *
 * @param {int} level (0-3) 0 -> 1/8, 1 -> 1/4 ....
 * @param {Object} match_id
 * @param {Array} score
 * @param {team_id} winner
 * @param {Object} name
 */
var insertKnockoutMatchBet = function(i_level, i_match, i_winner, i_score, i_name) {
    var parsedScore = [parseInt(i_score[0]), parseInt(i_score[1])];
    db.users.update({
        name : i_name,
        'knockout.match_id' : i_match
    }, {
        $set : {
            'knockout.$.score' : parsedScore,
            'knockout.$.winner' : i_winner
        }

    });

};

/**
 * This is an array to save time and NOT go to the DB everytime someone wants to see a betting level
 * It is saved that 0 is Final, and 3 is 1/8 but the input is 1 for Final and 4 for 1/8 so we need to bump +1
 */
//var knockoutLevelsAlreadyHere = [4];
/**
 * Gets the whole knockout level for ALL users
 */
var getKnockoutLevel = function(level, i_collection, callback) {
    db.users.aggregate([
    // Unwind the array
    {
        "$unwind" : "$knockout"
    },

    // Match the elements you want
    {
        "$match" : {
            "knockout.level" : level,
            "collection" : i_collection
        }
    },

    // Group back to the original form
    {
        "$group" : {
            "_id" : "$_id",
            "name" : {
                "$first" : "$name"
            },
            "knockout" : {
                "$push" : "$knockout"
            }
        }
    }], function(err, result) {
        if (err || !result) {
            //Error - this should not happen!
            console.log(err);
            callback(null);
        } else {
            //Puts the result in the array to save time next time
            //knockoutLevelsAlreadyHere[level + 1] = result;
            callback(result);
        }
    });

};

/**
 * Gets the whole knockout level for this users
 */
var getKnockoutLevelForUser = function(level, i_name, callback) {

    if (level == 0) {
        db.users.find({
            name : i_name
        }, {
            groups : 1
        }, function(err, result) {
            callback(result);
        });
    } else {
        db.users.aggregate([
        // Unwind the array
        {
            "$unwind" : "$knockout"
        },

        // Match the elements you want
        {
            "$match" : {
                'name' : i_name,
                "knockout.level" : level
            }
        },

        // Group back to the original form
        {
            "$group" : {
                "_id" : "$_id",
                "name" : {
                    "$first" : "$name"
                },
                "knockout" : {
                    "$push" : "$knockout"
                }
            }
        }], function(err, result) {
            if (err || !result) {
                //Error - this should not happen!
                console.log(err);
                callback(null);
            } else {
                //This holds the objects
                callback(result[0]);
            }
        });
    }

};

//var groupsAlreadyHere = [];
var groups = ["World Cup, Group A", "World Cup, Group B", "World Cup, Group C", "World Cup, Group D", "World Cup, Group E", "World Cup, Group F", "World Cup, Group G", "World Cup, Group H"];
/**returns group stage bets of all players - including SUDO
 *@return an array of users {name:<name>,groups:[{match_id:}]}
 *
 */
var getGroupLevel = function(groupName, i_collection, callback) {
    //  if (groupsAlreadyHere[groups.indexOf(groupName)] == null) {
    //This Means this group level has not been called yet (or has but the server fell) - Only then get it from the DB
    db.users.aggregate([
    // Unwind the array
    {
        "$unwind" : "$groups"
    },

    // Match the elements you want
    {
        "$match" : {
            "groups.groupName" : groupName,
            "collection" : i_collection
        }
    },

    // Group back to the original form
    {
        "$group" : {
            "_id" : "$_id",
            "name" : {
                "$first" : "$name"
            },
            "groups" : {
                "$push" : "$groups"
            }
        }
    }], function(err, result) {
        if (err || !result) {
            //Error - this should not happen!
            console.log(err);
            callback(null);
        } else {
            //Put result in the array - to save time for next time
            //groupsAlreadyHere[groups.indexOf(groupName)] = result;

            callback(result);
        }
    });
    //} else {
    //A client has asked for this bet level already - so bring it

    //   callback(groupsAlreadyHere[groups.indexOf(groupName)]);
    //  }

};
/**
 * Gets the tournament info for all users
 */
var getTournamentInfo = function(i_collection, callback) {
    db.users.find({
        collection : i_collection
    }, {
        champion : 1,
        leastGoalsConceded : 1,
        mostGoalsScored : 1,
        mvp : 1,
        kingOfGoals : 1,
        kingOfAssists : 1,
        name : 1,
        points : 1,
    }, function(err, result) {
        if (err || !result) {
            //User doesn't exist
            callback(null);
        } else {
            //Found user
            callback(result);
        }
    });
};

/**
 * Take points from this player
 * This does NOT open the game - just gives the points
 * @param {Object} level - a rules object for this level
 * @param {String} Player name to give points to
 */
var takePoints = function(level, player) {
    var pointsToTake = level.costToOpen;
    db.users.update({
        name : player
    }, {
        $inc : {
            points : pointsToTake * -1
        }
    });
};
/***
 * Give points for winner and for score
 *  @param level from the rules array
 * @param match_id to compare with sudo
 */
var givePointsKnockout = function(level, match_id) {
    var pointsToGive = level.pointsToGive;
    var pointsForBullseye = level.bullseye;
    getKnockoutMatchBet(match_id, sudo, function(result) {
        if (result == null) {
            //Match has not ended because sudo doesn't hold the score
            //TODO: What to do??
        } else {
            //Sudo holds the score and winner
            var score = result.score;
            var winner = result.winner;

            //Holds the mark flag (incase of Sudo) and makes sure this game doesn't get points twice
            var marked = result.marked;
            if (marked) {
                //Game has been marked before!
                console.log('Error: Points have already been given out for this knockout game - ' + match_id);
            } else {
                console.log("Giving out knockout points for match - " + match_id);
                //Game is new! GOOD
                db.users.update({
                    "knockout" : {
                        "$elemMatch" : {
                            "match_id" : match_id,
                            "score" : score,
                            "winner" : winner,
                            "home" : true,
                            "away" : true,
                        }
                    }
                }, {
                    "$inc" : {
                        "points" : pointsForBullseye
                    }
                }, {
                    multi : true
                });

                //Users who only guessed the winner but not the score (some users will be updated twice)
                db.users.update({
                    "knockout" : {
                        "$elemMatch" : {
                            "match_id" : match_id,
                            "winner" : winner,
                            "home" : true,
                            "away" : true,
                        }
                    }
                }, {
                    "$inc" : {
                        "points" : pointsToGive
                    }
                }, {
                    multi : true
                });

                //Make the marked TRUE so points won't be given again for this game
                sudoMarkGame(1, match_id);

                //Mark that these players got points for something!
                db.users.update({
                    "knockout" : {
                        $elemMatch : {
                            'match_id' : match_id,
                            'score' : score
                        }
                    }
                }, {
                    $set : {
                        'knockout.$.gotPoints' : true
                    }
                });

                //Mark that these players got points for something!
                db.users.update({
                    "knockout" : {
                        $elemMatch : {
                            'match_id' : match_id,
                            'winner' : winner
                        }
                    }
                }, {
                    $set : {
                        'knockout.$.gotPoints' : true
                    }
                });
            }

        }
    });

};
/**
 * Give points only for exact score
 * @param level from the rules array
 * @param match_id to compare with sudo
 */
var givePointsGroupStage = function(level, match_id) {
    var pointsForBullseye = level.bullseye;
    //Get Real score from Sudo
    getGroupMatchBet(match_id, sudo, function(result) {
        if (result == null) {
            console.log("Can't give points - game not over");
            //The game isn't in sudo yet - so the game has not been updated yet
            //TODO: what to do?

        } else {

            //Sudo holds the score
            var score = result.score;
            //Makes sure if points have been given for this match already
            var marked = result.marked;

            if (marked) {
                //users already got their points for this game
                console.log('Error: Points have already been given out for this game - ' + match_id);
            } else {
                //Update players that matched the score exactly
                db.users.update({
                    "groups" : {
                        "$elemMatch" : {
                            "match_id" : match_id,
                            "score" : score
                        }
                    }
                }, {
                    "$inc" : {
                        "points" : pointsForBullseye
                    }
                }, {
                    multi : true
                }, function(err, done) {
                    //When done updating group match
                    console.log("Finished giving points group match for - " + match_id);
                    //Make the marked TRUE so points won't be given again for this game
                    sudoMarkGame(-1, match_id);

                });

            }
            //Mark that these players got points for something!
            db.users.update({
                "groups" : {
                    '$elemMatch' : {
                        'match_id' : match_id,
                        'score' : score
                    }
                }
            }, {
                '$set' : {
                    'groups.$.gotPoints' : true
                }
            }, {
                multi : true
            });

        }
    });
};

/**
 * This function reads the qualifiers from Sudo and gives points for the qualifiers
 */
var givePointsQualifiers = function(level, groupName) {
    var pointsForQualify = level.qualifier;
    var pointsForBullseye = level.qualifierBullseye;
    db.users.findOne({
        name : sudo,
        'qualifiers.groupName' : groupName
    }, {
        'qualifiers.$' : 1
    }, function(err, result) {
        if (result == null) {
            console.log("Error getting the qualifiers for Sudo on - " + groupName);
        } else {
            //Sudo's qualifiers were found - now we give out points only if it hasn't been marked!
            var sudoFirst = result.qualifiers[0].rankedFirst;
            var sudoSecond = result.qualifiers[0].rankedSecond;

            //Makes sure if points have been given for this match already
            var marked = result.marked;

            if (marked) {
                //users already got their points for this qualifier
                console.log('Error: Points have already been given out for this qualifier - ' + groupName);
            } else {
                console.log("Giving out points for this qualifier - " + groupName);

                // ** SPLIT UPDATES TO 4 DIFFERENT STAGES ** //
                //This is first ranked = first ranked, give bullseye qualifier points
                db.users.update({
                    "qualifiers" : {
                        "$elemMatch" : {
                            "groupName" : groupName,
                            "rankedFirst" : sudoFirst
                        }
                    }
                }, {
                    "$inc" : {
                        "points" : pointsForBullseye
                    }
                }, {
                    multi : true
                });

                //This is first ranked = second ranked, give qualifier points
                db.users.update({
                    "qualifiers" : {
                        "$elemMatch" : {
                            "groupName" : groupName,
                            "rankedSecond" : sudoFirst
                        }
                    }
                }, {
                    "$inc" : {
                        "points" : pointsForQualify
                    }
                }, {
                    multi : true
                });

                //This is second ranked = second ranked, give bullseye qualifier points
                db.users.update({
                    "qualifiers" : {
                        "$elemMatch" : {
                            "groupName" : groupName,
                            "rankedSecond" : sudoSecond
                        }
                    }
                }, {
                    "$inc" : {
                        "points" : pointsForBullseye
                    }
                }, {
                    multi : true
                });

                //This is second ranked = first ranked, give qualifier points
                db.users.update({
                    "qualifiers" : {
                        "$elemMatch" : {
                            "groupName" : groupName,
                            "rankedFirst" : sudoSecond
                        }
                    }
                }, {
                    "$inc" : {
                        "points" : pointsForQualify
                    }
                }, {
                    multi : true
                });

                //Mark that these players got points for something!
                // markGotPointsQualifiers(groupName, sudoFirst, sudoSecond);

                //Make the marked TRUE so points won't be given again for this qualifier
                sudoMarkGame(0, groupName);

            }
        }
    });

};
/**
 *Gives all the users points based on Sudo
 */
var givePointsTournamentBets = function(rule) {
    db.users.findOne({
        name : sudo
    }, {
        mvp : 1,
        champion : 1,
        kingOfGoals : 1
    }, function(err, realPicks) {
        if (err || !realPicks) {
            console.log("users: Err getting Sudo's choices - " + err);

        } else {
            var realMvp = realPicks.mvp;
            var realChamp = realPicks.champion;
            var realKingOfGoals = realPicks.kingOfGoals;

            //Give points for MVP
            db.users.update({
                mvp : realMvp
            }, {
                $inc : {
                    points : rule.mvp
                }
            }, {
                multi : true
            });

            //Mark him
            db.users.update({
                mvp : realMvp
            }, {
                $set : {
                    gotPointsMvp : true
                }
            }, {
                multi : true
            });

            //Give points for Champion
            db.users.update({
                champion : realChamp
            }, {
                $inc : {
                    points : rule.champions
                }
            }, {
                multi : true
            });

            //Mark him
            db.users.update({
                champion : realChamp
            }, {
                $set : {
                    gotPointsChampion : true
                }
            }, {
                multi : true
            });

            //Give points for Golden Boot
            db.users.update({
                kingOfGoals : realKingOfGoals
            }, {
                $inc : {
                    points : rule.kingOfGoals
                }
            }, {
                multi : true
            });

            //Mark him
            db.users.update({
                kingOfGoals : realKingOfGoals
            }, {
                $set : {
                    gotPointsKingOfGoals : true
                }
            }, {
                multi : true
            });

        }
    });
};

/**
 * Iterates over players and sees if their qualifiers match sudo's qualifiers - if so, makes the home or away in to true in the next match id
 * This assumes that the team that was ranked first is playing as teamA in the 1/8
 * */
var lockGroupGames = function(i_groupName, i_nextMatches_id) {
    //This is where Sudo marked the teams that have made it to the next stage
    var firstNextMatch_id = i_nextMatches_id.firstMatch;
    var secondNextMatch_id = i_nextMatches_id.secondMatch;

    db.users.find({
        name : sudo,
        'qualifiers.groupName' : i_groupName
    }, {
        'qualifiers.$.rankedFirst' : 1
    }, function(err, sudoPicks) {
        if (err || !sudoPicks) {
            console.log("Couldn't find Sudo's qualifiers for - " + i_groupName);
        } else {
            //Get Sudo's picks
            console.log("Found Sudo's qualifiers for - " + i_groupName);
            var realRankedFirst = sudoPicks[0].qualifiers[0].rankedFirst;
            var realRankedSecond = sudoPicks[0].qualifiers[0].rankedSecond;
            //Iterate over players and check if they also picked the rank first (as one of the picks) and the ranked second (as one of the picks)
            db.users.find({
                $or : [{
                    "qualifiers" : {
                        "$elemMatch" : {
                            "groupName" : i_groupName,
                            "rankedFirst" : realRankedFirst
                        }
                    }
                }, {
                    "qualifiers" : {
                        "$elemMatch" : {
                            "groupName" : i_groupName,
                            "rankedSecond" : realRankedFirst
                        }
                    }
                }],

            }, {
                'name' : 1,
                _id : 0,
            }, function(e, matchedPlayersFirst) {
                if (e) {
                    console.log(e);
                }
                if (matchedPlayersFirst == 1) {
                    console.log("No users picked " + realRankedFirst + " as advancing to the 1/8");
                } else {
                    //Iterate over matches
                    console.log(matchedPlayersFirst.length - 1 + " users put " + realRankedFirst + " as a qualifier");
                    for (var i = 0; i < matchedPlayersFirst.length; i++) {
                        var tempName = matchedPlayersFirst[i].name;

                        //Make  the teamA: true for the matched players on the nextMatch_id - teamA because the team will play home
                        if (tempName != sudo) {
                            console.log('Opening home game for - ' + tempName);
                            db.users.update({
                                name : tempName,
                                'knockout.match_id' : firstNextMatch_id
                            }, {
                                $set : {
                                    'knockout.$.home' : true
                                }

                            });

                        }
                    }
                }
            });

            //Iterate over players and check if they also picked the rank first (as one of the picks) and the ranked second (as one of the picks)
            db.users.find({
                $or : [{
                    "qualifiers" : {
                        "$elemMatch" : {
                            "groupName" : i_groupName,
                            "rankedFirst" : realRankedSecond
                        }
                    }
                }, {
                    "qualifiers" : {
                        "$elemMatch" : {
                            "groupName" : i_groupName,
                            "rankedSecond" : realRankedSecond
                        }
                    }
                }],

            }, {
                'name' : 1,
                _id : 0,
            }, function(e, matchedPlayersSecond) {
                if (e) {
                    console.log(e);
                }
                if (matchedPlayersSecond == 1) {
                    console.log("No users picked " + realRankedSecond + " as advancing to the 1/8");
                } else {
                    //Iterate over matches
                    console.log(matchedPlayersSecond.length - 1 + " users put " + realRankedSecond + " as a qualifier");

                    for (var i = 0; i < matchedPlayersSecond.length; i++) {
                        var tempName = matchedPlayersSecond[i].name;

                        //Make  the teamB: true for the matched players on the nextMatch_id - (teamB because the team will play home)
                        if (tempName != sudo) {
                            console.log('Opening away game for - ' + tempName);
                            db.users.update({
                                name : tempName,
                                'knockout.match_id' : secondNextMatch_id
                            }, {
                                $set : {
                                    'knockout.$.away' : true
                                }

                            });

                        }
                    }
                }
            });
        }
    });

};

/**
 * Iterates over players and sees if their winner match sudo's winner for this level - if so, makes the teamA or teamB in to true in the next match
 */
var lockKnockoutGame = function(i_previousMatch_id, i_nextMatchObject) {
    var realWinner = null;
    db.users.find({
        name : sudo,
        'knockout.match_id' : i_nextMatchObject.id
    }, {
        'knockout.$.level' : 1
    }, function(err, sudoPick) {
        if (err || !sudoPick) {
            console.log(err);
        } else {
            if (i_nextMatchObject.home) {
                //Team is inside teamA return of sudoPick
                realWinner = sudoPick[0].knockout[0].home;
            } else {
                realWinner = sudoPick[0].knockout[0].away;
            }
            //Scan users to see if they put this winner in the previous match
            db.users.find({
                "knockout" : {
                    "$elemMatch" : {
                        "match_id" : i_previousMatch_id,
                        "winner" : realWinner
                    }
                }
            }, {
                'name' : 1,
                _id : 0,
            }, function(error, matchingUsers) {
                if (matchingUsers.length <= 1) {
                    //No users guessed the winner! - sudo counts so it needs to be more than 1
                    console.log("No users picked - " + realWinner + " as going to the next stage");
                } else {
                    console.log("Opening next match to users who picked - " + realWinner);
                    for (var i = 0; i < matchingUsers.length; i++) {
                        //Iterate over matching users and give their teamA/teamB field true
                        var currentName = matchingUsers[i].name;

                        if (currentName != sudo) {
                            //Don't flag Sudo!
                            console.log("Opening next game for - " + currentName);
                            //Need to know which field to update in the users, teamA or teamB
                            if (i_nextMatchObject.home) {
                                //Update teamA
                                db.users.update({
                                    name : currentName,
                                    'knockout.match_id' : i_nextMatchObject.id
                                }, {
                                    $set : {
                                        'knockout.$.home' : true
                                    }
                                });
                            } else {
                                //Update teamB
                                db.users.update({
                                    name : currentName,
                                    'knockout.match_id' : i_nextMatchObject.id
                                }, {
                                    $set : {
                                        'knockout.$.away' : true
                                    }

                                });
                            }
                        }

                    }
                }

            });
        }

    });
};

/**
 * Private function - after giving points - mark this game so points won't be given again!
 */
function sudoMarkGame(knockoutGroupQual, match_id) {
    //Insert the sudo bet as the real score
    if (knockoutGroupQual == -1) {
        //Mark a group
        db.users.update({
            name : sudo,
            "groups.match_id" : match_id
        }, {
            $set : {
                "groups.$.marked" : true /** Guarantees that points won't be given twice! **/
            }
        });
    } else if (knockoutGroupQual == 1) {
        //Mark a knockout
        db.users.update({
            name : sudo,
            "knockout.match_id" : match_id
        }, {
            $set : {
                "knockout.$.marked" : true /** Guarantees that points won't be given twice! **/
            }
        });
    } else {
        //Mark a qualifier
        db.users.update({
            name : sudo,
            "qualifiers.groupName" : match_id
        }, {
            $set : {
                "qualifiers.$.marked" : true /** Guarantees that points won't be given twice! **/
            }
        });
    }

}

/**
 * Before a player places a bet - this validates if he can
 * @param player name
 * @param match_id to bet on
 * @param callback true if can bet, false if he can NOT
 */
var validateBeforeBet = function(name, match_id, callback) {
    db.users.find({
        name : name,
        "knockout" : {
            "$elemMatch" : {
                "match_id" : match_id,
                'home' : true,
                'away' : true
            }
        }
    }, function(err, result) {
        if (!result || result.length < 1) {
            //This means the player can NOT bet because not both his teams are true
            console.log(name + " is not allowed to bet on - " + match_id);
            callback(false);

        } else {
            //Player was found - so he can bet
            console.log(name + " can bet on - " + match_id);
            callback(true);
        }
    });
};

/**
 * This function opens this match for this user
 * @param name of User
 * @param match_id to open
 * @param homeBool home if true, away if false
 */
var openGameForUser = function(name, match_id, homeBool) {
    if (homeBool) {
        //Open home team
        db.users.update({
            name : name,
            'knockout.match_id' : match_id
        }, {
            $set : {
                'knockout.$.home' : true
            }
        });
    } else {
        db.users.update({
            name : name,
            'knockout.match_id' : match_id
        }, {
            $set : {
                'knockout.$.away' : true
            }
        });
    }

};

/**
 * init function fills up the user with all the groups and knockout matches
 * @warning: it empties all the bets
 */
function init(name) {
    //Get all Group matches and append them to all users
    api.getAllGroupMatches(function(result) {
        db.users.update({
            name : name
        }, {
            $set : {
                groups : result
            }
        });

    });

    //Get all the knockout matches and append them to all the users
    api.getAllKnockoutMatches(function(result) {
        db.users.update({
            name : name
        }, {
            $set : {
                knockout : result
            }
        });
    });
    //Inits the empty qualifiers array
    var result = syncQualifiers();
    db.users.update({
        name : name
    }, {
        $set : {
            qualifiers : result
        }
    });

}

/**
 * Returns the match details for THIS player only
 * @param {Object} match_id
 * @param {Object} name
 */
var getGroupMatchBet = function(match_id, name, callback) {
    db.users.find({
        name : name,
        'groups.match_id' : match_id
    }, {
        'groups.$.score' : 1,
        _id : 0,
        marked : 1, /** Only for Sudo **/
    }, function(err, res) {
        if (err || !res || res < 1) {
            //User hasn't placed any bets on this game yet
            callback(null);

        } else {
            callback(res[0].groups[0]);
        }

    });
};

/**
 * Returns the match details for THIS player only
 * @param {Object} match_id
 * @param {Object} name
 */
var getKnockoutMatchBet = function(match_id, name, callback) {
    db.users.find({
        name : name,
        'knockout.match_id' : match_id
    }, {
        'knockout.$.score' : 1,
        _id : 0,
    }, function(err, res) {
        if (err || !res || res < 1) {
            //User hasn't placed any bets on this game yet
            console.log(err);
            callback(null);

        } else {
            callback(res[0].knockout[0]);
        }

    });
};

/**
 * Returns the match details for THIS player only
 * @param {Object} groupName
 * @param {Object} name of user
 */
var getQualifiersBet = function(i_groupName, i_collection, callback) {
    db.users.find({
        'qualifiers.groupName' : i_groupName,
        'collection' : i_collection
    }, {
        'qualifiers.$.rankedFirst' : 1,
        name : 1,
    }, function(err, res) {
        if (err || !res || res < 1) {
            //User hasn't placed any qualifiers on this group yet
            callback(null);

        } else {
            callback(res);
        }

    });
};

var allQualifiers = null;
var syncQualifiers = function() {
    if (allQualifiers == null) {
        console.log("No Previous Qualifiers");
        //Build the qualifiers array
        var returnObject = [];
        var groups = ["A", "B", "C", "D", "E", "F", "G", "H"];
        for (var i = 0; i < 8; i++) {
            //Build 8 empty qualifiers objects and send the array
            var toPush = {
                groupName : "World Cup, Group " + groups[i],
                rankedFirst : null,
                rankedSecond : null
            };
            returnObject.push(toPush);
        }
        allQualifiers = returnObject;
    }
    return allQualifiers;

};

/**
 * Private function that gives users a gotPoints:true on the right qualifiers
 * @param {Object} i_groupName
 */
function markGotPointsQualifiers(i_groupName, sudoFirst, sudoSecond) {
    db.users.update({
        "qualifiers" : {
            "$elemMatch" : {
                "groupName" : i_groupName,
                "rankedFirst" : sudoFirst
            }
        }
    }, {
        "$set" : {
            "qualifiers.$.gotPoints" : true
        }
    }, {
        multi : true
    });

    //This is first ranked = second ranked, give qualifier points
    db.users.update({
        "qualifiers" : {
            "$elemMatch" : {
                "groupName" : i_groupName,
                "rankedSecond" : sudoFirst
            }
        }
    }, {
        "$set" : {
            "qualifiers.$.gotPoints" : true
        }
    }, {
        multi : true
    });

    //This is second ranked = second ranked, give bullseye qualifier points
    db.users.update({
        "qualifiers" : {
            "$elemMatch" : {
                "groupName" : i_groupName,
                "rankedSecond" : sudoSecond
            }
        }
    }, {
        "$set" : {
            "qualifiers.$.gotPoints" : true
        }
    }, {
        multi : true
    });

    //This is second ranked = first ranked, give qualifier points
    db.users.update({
        "qualifiers" : {
            "$elemMatch" : {
                "groupName" : i_groupName,
                "rankedFirst" : sudoSecond
            }
        }
    }, {
        "$set" : {
            "qualifiers.$.gotPoints" : true
        }
    }, {
        multi : true
    });

}

//Make the functions exportable
module.exports.insertKnockoutMatchBet = insertKnockoutMatchBet;
module.exports.insertTournamentBet = insertTournamentBet;
module.exports.insertQualifiersBet = insertQualifiersBet;
module.exports.insertGroupMatchBet = insertGroupMatchBet;
module.exports.givePointsGroupStage = givePointsGroupStage;
module.exports.givePointsKnockout = givePointsKnockout;
module.exports.init = init;
module.exports.signup = signup;
module.exports.login = login;
module.exports.listAllUsers = listAllUsers;
module.exports.takePoints = takePoints;
module.exports.getKnockoutLevel = getKnockoutLevel;
module.exports.getQualifiersBet = getQualifiersBet;
module.exports.getKnockoutMatchBet = getKnockoutMatchBet;
module.exports.getGroupMatchBet = getGroupMatchBet;
exports.syncQualifiers = syncQualifiers;
exports.getTournamentInfo = getTournamentInfo;
exports.givePointsQualifiers = givePointsQualifiers;
exports.lockGroupGames = lockGroupGames;
exports.lockKnockoutGame = lockKnockoutGame;
exports.getGroupLevel = getGroupLevel;
exports.validateBeforeBet = validateBeforeBet;
exports.getKnockoutLevelForUser = getKnockoutLevelForUser;
exports.isGameOpenable = isGameOpenable;
exports.openGameForUser = openGameForUser;
exports.userExists = userExists;
exports.collectionExists = collectionExists;
exports.loginCollection = loginCollection;
exports.listWorldUsers = listWorldUsers;
exports.removeCollectionFromUser = removeCollectionFromUser;
exports.givePointsTournamentBets = givePointsTournamentBets;
exports.editProfile = editProfile;
exports.userProfile = userProfile;
